#include "ExtentIO.h"
#include "SimulationParameters.h"
#include <sstream>
#include <iostream>
using namespace std;
static int id = 1;

// TODO: fix getSize to handle io that spread over 2 slots (or more) with small size example: offset 7, size 2 - now we bring only 1 chunk and we should bring 2

ExtentIO::ExtentIO( double time, IOType type, int lunID, long offset, int size, bool real) : 
_time( time) , _type(type), _lunID(lunID), _realOffset(offset), _size(size), _sequential(false), _real(real), _isHit(false)
{
	// _offset is in kilobytes (not blocks)
	_offset = (long)(floor((offset / 2.0)/  SimulationParameters::CacheAlignment) * SimulationParameters::CacheAlignment);
	ExtentId = id++;
	_fromWrite=false;
}
ExtentIO::ExtentIO( const ExtentIO& other) : _time( other._time) , _type(other._type), _lunID(other._lunID), _realOffset(other._realOffset), _offset(other._offset), _size(other._size),
	_sequential(other._sequential), _real(other._real), _fromWrite(other._fromWrite)
{
}

ExtentIO::~ExtentIO(void)
{
}


double ExtentIO::getTime() const
{
	return _time;
}
IOType ExtentIO::getType() const
{
	return _type;
}
int ExtentIO::getLunID() const
{
	return _lunID;
}
long ExtentIO::getOffset() const
{
	return _offset;
}
long ExtentIO::getRealOffset() const
{
	return _realOffset;
}
int ExtentIO::getSize(int align) const
{
	return getSizeAligned(align);
}

int ExtentIO::getSizeAligned(int align) const
{
	int size = (int)(ceil((_size / 2.0)/ align));
	return size;
}

int ExtentIO::getSizeBlocks() const
{
	return _size;
}
 
bool ExtentIO::isSequential() const
{
	return _sequential;
}

bool ExtentIO::isReal() const
{
	return _real;
}

bool ExtentIO::isFromWrite(){
	return _fromWrite;
}

void ExtentIO::setFromWrite(){
	_fromWrite=true;
}

void ExtentIO::setSequential(bool b)
{
	_sequential=b;
}

string ExtentIO::getIOID(int align) const
{
	int offset = floor((double)_offset / align)*align;
	stringstream s;
	s << _lunID << "," << offset;
	return s.str();
}

string ExtentIO::getExtentID() const
{
	stringstream s;
	int align = EXTENT_SIZE/KB;
	long extentOffset = (long)(floor( ((double)_offset) / (align))*align);
	s << _lunID << "," << extentOffset;
	return s.str();
}

double ExtentIO::getSizeMB(double align) const
{
	// _size /2 - gets number of KB
	// (_size /2.0) / align - gets number of align KB units
	// ceil ((_size /2) / align) round up to align KB alignment
	// (ceil((_size /2.0) / align ) *align - gets the number of KB to retrieve
	// (ceil((_size /2.0) / align ) *align ) / 1024.0) - transfer the data to MB
	if (_size < 0)
	{
		std::cout << "Fashla - negative size!!!\n";
		throw "Fashla - negative size!!!";
	}
	double ans = (ceil((_size / 2.0) / align ) * align) / (double)KB; 
	return ans;
}

void ExtentIO::setOffset(long offset)
{
	_offset = offset;
}
void ExtentIO::setReal(bool isReal)
{
	_real = isReal;
}

void ExtentIO::setType(IOType type)
{
	_type = type;
}
bool ExtentIO::isHit() const
{
	return _isHit;
}
void ExtentIO::hit() 
{
	_isHit = true;
}